package project2;

import java.util.ArrayList;

import misc.not_Legal_Exception;
import evolution_superclasses.Genotype;
import evolution_superclasses.Phenotype;

public class spiking_neuron_phenotype extends Phenotype {
	protected double[] _params;
	protected double[] _spikeTrain;
	protected ArrayList<Integer> _spikeTimeTrain;
	
	private double v, u;

	public spiking_neuron_phenotype(Genotype gen) {
		super(gen);
	}

	public double[] get_params() {
		return _params;
	}

	public void set_params(double[] params) {
		_params = params;
	}

	public double[] get_spikeTrain() {
		return _spikeTrain;
	}

	public void set_spikeTrain(double[] spikeTrain) {
		_spikeTrain = spikeTrain;
	}


	@Override
	protected void develop(Genotype gen) throws not_Legal_Exception {
		if(gen.get_genSize()!=5)throw new not_Legal_Exception("spiking neurons should only have 5 parameters.");
		_params = new double[5];
		
		int[] intParams = ((spiking_neuron_genotype)gen).get_params();
		for(int i = 0; i < intParams.length; i++)
			_params[i] = (double)intParams[i]/1000;
		calculateSpikeTrain();
		setSpikeTimeTrain();
	}

	private void calculateSpikeTrain(){ 
		int maxtimesteps = 1000, step = -1;
		double derV, derU, T = 10, I = 10;
		v = -60; u = 0;
		_spikeTrain = new double[1001];
		while(step++ < maxtimesteps){
			derV = (1/T)*(_params[4]*v*v+5*v+140-u+I);	// 1/T(kv^2+5v+140-u+I)
			derU = (_params[0]/T)*(_params[1]*v-u);		// a/T(bv-u)
			v += derV;
			u += derU;
			_spikeTrain[step] = v;
			if(v > 35)reset();
		}
	}
	
	private void reset(){
		v = _params[2];//c
		u = u + _params[3];//d
	}

	public void setSpikeTimeTrain(){ 
		//window = 5, hence the hard coded bits
		//Threshold = 0
		_spikeTimeTrain = new ArrayList<Integer>();
		int i = 2;
		if(_spikeTrain[0] > _spikeTrain[1] && _spikeTrain[0] > _spikeTrain[2] && _spikeTrain[0] > 0){
			_spikeTimeTrain.add(0);
		}else if(_spikeTrain[1] > _spikeTrain[2] && _spikeTrain[1] > _spikeTrain[3] && _spikeTrain[1] > 0){
			_spikeTimeTrain.add(1);
			i=4;
		}
		
		while(i < _spikeTrain.length-2){
			if(_spikeTrain[i] > _spikeTrain[i-2] && _spikeTrain[i] > _spikeTrain[i-1]
			&& _spikeTrain[i] > _spikeTrain[i+1] && _spikeTrain[i] > _spikeTrain[i+2]
			&& _spikeTrain[i] > 0){
				_spikeTimeTrain.add(i);
				i+=3;//can be no close ones.
			}else{
				i++;
			}
		}
		i = _spikeTrain.length-2;
		if(_spikeTrain[i] > _spikeTrain[i-2] && _spikeTrain[i] > _spikeTrain[i-1]
		&& _spikeTrain[i] > _spikeTrain[i+1] && _spikeTrain[i] > 0){
			_spikeTimeTrain.add(i);
			i+=3;//can be no close ones.
		}else if(_spikeTrain[++i] > _spikeTrain[i-2] && _spikeTrain[i] > _spikeTrain[i-1]
          && _spikeTrain[i] > 0){
			_spikeTimeTrain.add(i);
			i+=3;//can be no close ones.
		}
		
	}

	public ArrayList<Integer> get_spikeTimeTrain() {
		return _spikeTimeTrain;
	}

	@Override
	public String toString() {
		return "a: "+_params[0]+"\nb: "+_params[1]+"\nc: "+_params[2]+"\nd: "+_params[3]+"\nk: "+_params[4];
	}
}
